package com.linkhub.oms.admin.modules.track.service;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.google.common.collect.Lists;
import com.linkhub.oms.admin.modules.order.domain.vo.OrderTabCountVO;
import com.linkhub.oms.admin.modules.order.service.OrderInfoAssembleService;
import com.linkhub.oms.admin.modules.satoken.session.LhSessionContext;
import com.linkhub.oms.admin.modules.track.domain.param.OrderTrackQueryParam;
import com.linkhub.oms.admin.modules.track.domain.request.TrackRequest;
import com.linkhub.oms.admin.modules.track.domain.vo.OrderTrackListVo;
import com.linkhub.oms.admin.modules.track.domain.vo.TrackExportResultVO;
import com.linkhub.oms.admin.modules.track.util.OrderTrackMappingAssist;
import com.linkhub.oms.common.enums.IEnumConvert;
import com.linkhub.oms.common.enums.mp.*;
import com.linkhub.oms.common.response.PageDTO;
import com.linkhub.oms.common.util.QtOptionalUtil;
import com.linkhub.oms.common.util.QtStreamUtil;
import com.linkhub.oms.component.mp.util.QtMybatisPlusUtil;
import com.linkhub.oms.component.mp.wrapper.WrapperConverter;
import com.linkhub.oms.dao.mapper.OrderEntityMapper;
import com.linkhub.oms.dao.mpservice.IOrderService;
import com.linkhub.oms.dao.mpservice.IOrderTrackService;
import com.linkhub.oms.entity.*;
import com.linkhub.oms.entity.innerproperties.TrackEventInfoEntity;
import com.linkhub.oms.entity.resulttype.order.OrderInfoDO;
import com.opencsv.CSVWriter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static com.linkhub.oms.common.constant.FileConstant.EXPORT_WAYBILL_TRACKING_FILE_NAME;

/**
 * @author Redball
 * @version 1.0.0
 * @Description OrderTrackServiceImpl
 * @createTime 2024/10/26 下午3:02
 */
@Slf4j
@Service
public class OrderTrackBizServiceImpl implements OrderTrackBizService {

    @Resource
    private IOrderService orderService;
    @Resource
    private OrderInfoAssembleService orderInfoAssembleService;
    @Resource
    private IOrderTrackService orderTrackService;

    @Resource
    private OrderEntityMapper orderEntityMapper;

    @Override
    public PageDTO<OrderTrackListVo> pageOrders(OrderTrackQueryParam orderQueryParam) {

        List<String> sysShopIds = orderQueryParam.getSysShopIds();
        List<String> orderNumbers = null;
        if(StringUtils.isNotBlank(orderQueryParam.getOrderNumber())){
            orderNumbers = Arrays.asList(orderQueryParam.getOrderNumber().split(","));
        }
        List<String> wayBillNumbers = null;
        if(StringUtils.isNotBlank(orderQueryParam.getWayBillNumber())){
            wayBillNumbers = Arrays.asList(orderQueryParam.getWayBillNumber().split(","));
        }

        TrackBusinessStatusEnum trackBusinessStatusEnum = IEnumConvert.valueOf(orderQueryParam.getTabType(),TrackBusinessStatusEnum.class);
        Page<OrderEntity> page = orderService.lambdaQuery()
                .in(CollUtil.isNotEmpty(sysShopIds), OrderEntity::getSysShopId, sysShopIds)
                .eq(OrderEntity::getEmployeeBusinessStatus, EmployeeBusinessStatusEnum.TRACKING)
                .eq(OrderEntity::getTrackBusinessStatus, trackBusinessStatusEnum)
                .in(CollUtil.isNotEmpty(orderNumbers), OrderEntity::getOrderNumber,orderNumbers)
                .in(CollUtil.isNotEmpty(wayBillNumbers), OrderEntity::getWayBillNumber,wayBillNumbers)
                .eq(OrderEntity::getDataStatus, DataStatusEnum.ENABLE)
                .orderByDesc(OrderEntity::getDeliveryTime)
                .orderByDesc(OrderEntity::getCreatedAtConvert)
                .page(new Page<>(orderQueryParam.getPage(), orderQueryParam.getSize()));

        if (CollUtil.isEmpty(page.getRecords())) {
            return QtMybatisPlusUtil.convertPage(page, null);
        }

        List<OrderInfoDO> orders = orderInfoAssembleService.assembleOrderInfos(page.getRecords());
        for (OrderInfoDO orderInfoDO : orders) {
            OrderEntity order = orderInfoDO.getOrder();
            OrderTrackEntity orderTrackEntity = orderTrackService.lambdaQuery()
                    .eq(OrderTrackEntity::getNumber,order.getWayBillNumber())
                    .one();
            orderInfoDO.setOrderTrack(orderTrackEntity);
        }
        Map<String, OrderInfoDO> orderInfoMap = QtStreamUtil.toMap(orders, OrderInfoDO::getSysOrderId);
        return QtMybatisPlusUtil.convertPage(page,
                order -> OrderTrackMappingAssist.mappingTrackOrderlist(orderInfoMap.get(order.getSysOrderId())));
    }

    @Override
    public List<OrderTabCountVO> getTabCount() {
        List<String> shopIds = null;
        if(LhSessionContext.isCustomerRole()) {
            shopIds = LhSessionContext.getUserShopIds();
        }
        LambdaQueryWrapper<OrderEntity> lambdaQuery = Wrappers
                .lambdaQuery(OrderEntity.class)
                .in(CollUtil.isNotEmpty(shopIds), OrderEntity::getSysShopId, shopIds)
                .eq(OrderEntity::getDataStatus, DataStatusEnum.ENABLE)
                .eq(OrderEntity::getEmployeeBusinessStatus, EmployeeBusinessStatusEnum.TRACKING)
                .isNotNull(OrderEntity::getTrackBusinessStatus)
                .groupBy(OrderEntity::getTrackBusinessStatus);

        QueryWrapper<OrderEntity> queryWrapper = WrapperConverter.convertLambdaCondition(lambdaQuery);
        queryWrapper.select("Ftrack_business_status, count(Fid) as count");

        List<OrderEntity> orders = orderService.list(queryWrapper);
        if (CollUtil.isEmpty(orders)) {
            return Lists.newArrayListWithCapacity(0);
        }
        return QtStreamUtil.map(orders, OrderTrackMappingAssist::mappingTrackTabCount);
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveOrderTrackInfo(TrackRequest trackRequest, OrderEntity orderEntity){
        TrackRequest.TrackInfo trackInfo = QtOptionalUtil.of(trackRequest.getTrackInfo()).orElse(new TrackRequest.TrackInfo());
        TrackRequest.TrackStatus latestStatus = QtOptionalUtil.of(trackInfo.getLatestStatus()).orElse(new TrackRequest.TrackStatus());
        TrackEventInfoEntity latestEvent = QtOptionalUtil.of(trackInfo.getLatestEvent()).orElse(new TrackEventInfoEntity());
        TrackRequest.TimeMetrics timeMetrics = QtOptionalUtil.of(trackInfo.getTimeMetrics()).orElse(new TrackRequest.TimeMetrics());
        TrackRequest.EstimatedDeliveryDate estimatedDeliveryDate = QtOptionalUtil.of(timeMetrics.getEstimatedDeliveryDate()).orElse(new TrackRequest.EstimatedDeliveryDate());
        TrackRequest.Tracking tracking = QtOptionalUtil.of(trackInfo.getTracking()).orElse(new TrackRequest.Tracking());
        List<TrackRequest.Provider> providers = tracking.getProviders();
        List<TrackEventInfoEntity> trackEvents = null;
        if(CollUtil.isNotEmpty(providers)){
            trackEvents = providers.get(0).getEvents();
        }

        OrderTrackEntity orderTrackEntity = orderTrackService.lambdaQuery()
                .eq(OrderTrackEntity::getNumber,trackRequest.getNumber())
                .one();

        OrderTrackEntity update = new OrderTrackEntity();
        if(orderTrackEntity!=null){
            update.setId(orderTrackEntity.getId());
        }
        update.setNumber(trackRequest.getNumber());
        update.setSysOrderId(orderEntity.getSysOrderId());
        update.setCarrier(trackRequest.getCarrier());
        update.setLatestStatus(latestStatus.getStatus());
        update.setLatestSubStatus(latestStatus.getSub_status());
        update.setLatestSubStatusDescr(latestStatus.getSubStatusDescr());
        update.setLatestEventDescription(latestEvent.getDescription());
        update.setLatestEventTimeUtc(latestEvent.getTimeUtc());
        update.setLatestEventTimeIso(latestEvent.getTimeIso());
        update.setLatestEventLocation(latestEvent.getLocation());
        update.setDaysAfterOrder(timeMetrics.getDaysAfterOrder());
        update.setDaysAfterLastUpdate(timeMetrics.getDaysAfterLastUpdate());
        update.setDaysOfTransit(timeMetrics.getDaysOfTransit());
        update.setDaysOfTransitDone(timeMetrics.getDaysOfTransitDone());
        update.setEstimatedDeliveryDateSource(estimatedDeliveryDate.getSource());
        update.setEstimatedDeliveryDateFrom(estimatedDeliveryDate.getFrom());
        update.setEstimatedDeliveryDateTo(estimatedDeliveryDate.getTo());
        update.setTrackEvents(trackEvents);

        orderTrackService.saveOrUpdate(update);

        OrderEntity orderUpdate = new OrderEntity();
        orderUpdate.setTrackBusinessStatus(Enum.valueOf(TrackBusinessStatusEnum.class,latestStatus.getStatus()));
        if(TrackBusinessStatusEnum.Delivered.equals(orderUpdate.getTrackBusinessStatus())){
            orderUpdate.setOrderStatus(OrderStatusEnum.HAVE_BEEN_SIGNED);
            orderUpdate.setEmployeeOrderStatus(EmployeeOrderStatusEnum.HAVE_BEEN_SIGNED);

        }
        orderService.updateOrderInfo(orderEntity.getSysOrderId(),orderUpdate);
    }

    @Override
    public void trackExportExcel( List<String> sysShopIds, HttpServletResponse response ) {
        String fileName;
        System.out.println(sysShopIds);
        try {
            fileName = URLEncoder.encode(EXPORT_WAYBILL_TRACKING_FILE_NAME, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"; filename*=utf-8''" + fileName);

        response.setContentType("text/csv");
        response.setCharacterEncoding("UTF-8");

        // 使用 StringWriter 缓存内容
        try (StringWriter stringWriter = new StringWriter();
             CSVWriter csvWriter = new CSVWriter(stringWriter)) {

            // 添加 CSV 头，订单号(手工订单或者平台订单号)、运单号、尾程追踪号 、物流渠道、发货日期（YYYY-MM-DD hh:mm:ss）
            String[] csvHeader = {"Shop Name", "Order Number", "Waybill Number", "Tracking Number", "Channel Name", "Delivery Time"};
            csvWriter.writeNext(csvHeader);

            MPJLambdaWrapper<OrderEntity> queryWrapper = new MPJLambdaWrapper<>();
            queryWrapper.select(ShopEntity::getShopName)       // 商店名称
                    .select(OrderEntity::getOrderNumber,       // 订单号
                            OrderEntity::getWayBillNumber,     // 运单号
                            OrderEntity::getTrackingNumber,    // 追踪号
                            OrderEntity::getDeliveryTime)     // 发货时间
                    .select(LogisticEntity::getChannelEName)   // 渠道英文名
                    .innerJoin(ShopEntity.class, ShopEntity::getSysShopId, OrderEntity::getSysShopId) // 关联 t_shop
                    .innerJoin(LogisticEntity.class, LogisticEntity::getChannelCode, OrderEntity::getChannelCode) // 关联 t_logistics_channel
                    .ge(OrderEntity::getFulfillmentTime, LocalDateTime.now().minusMonths(3)) // 履约时间在最近三个月
                    .isNotNull(OrderEntity::getWayBillNumber)  // 运单号不为空
                    .in(CollectionUtils.isNotEmpty(sysShopIds), OrderEntity::getSysShopId, sysShopIds)
                    .eq(ShopEntity::getUserId, LhSessionContext.getUserId());
            List<TrackExportResultVO> trackExportResultVOS = orderEntityMapper.selectJoinList(TrackExportResultVO.class, queryWrapper);

            // 写入 CSV 数据行
            for (TrackExportResultVO trackExportResultVO : trackExportResultVOS) {

                String[] data = {"=\"" + trackExportResultVO.getShopName() + "\"", // 商店名称
                        "=\"" + trackExportResultVO.getOrderNumber() + "\"", // 订单号
                        "=\"" + trackExportResultVO.getWayBillNumber() + "\"", // 运单号
                        "=\"" + ("null".equals(trackExportResultVO.getTrackingNumber()) || trackExportResultVO.getTrackingNumber() == null
                                ? "" : trackExportResultVO.getTrackingNumber()) + "\"", // 追踪号
                        "=\"" + trackExportResultVO.getChannelEName() + "\"", // 渠道英文名
                        "=\"" + ("null".equals(trackExportResultVO.getDeliveryTime()) || trackExportResultVO.getDeliveryTime() == null
                                ? "" : trackExportResultVO.getDeliveryTime()) + "\"", // 发货时间
                };
                csvWriter.writeNext(data);
            }

            // 所有数据成功写入到 StringWriter 后再输出到 HttpServletResponse
            try (PrintWriter writer = response.getWriter()) {
                writer.write(stringWriter.toString());
            }

        } catch (Exception e) {
            throw new RuntimeException("导出CSV文件失败", e);
        }
    }
}
